package org.jpropelleralt.list.impl;

import org.jpropelleralt.list.ListBox;
import org.jpropelleralt.plumbing.NoInstanceAvailableException;
import org.jpropelleralt.plumbing.Source;
import org.jpropelleralt.reaction.impl.ReactionDefault;
import org.jpropelleralt.ref.Ref;
import org.jpropelleralt.ref.impl.RefDefault;

/**
 * Allows for creation of a {@link Ref} that
 * contains the selected value in a {@link ListBox}
 */
public class ListSelection {

	/**
	 * Create a {@link Ref} that will always contain the
	 * element of a {@link ListBox} that is chose by an
	 * integer selection index.
	 * 
	 * {@link Ref} will have a value class.
	 * 
	 * @param <T>				The type of element in the {@link ListBox} 
	 * @param valueClass		The class of element in the {@link ListBox}
	 * @param list				The {@link Ref} to a {@link ListBox}
	 * @param selectionIndex	{@link Ref} to selected index
	 * @return					A {@link Ref} that always contains the selected element, or
	 * 							null if selectionIndex is -1 or outside list.
	 */
	public static <T> Ref<T> create(Class<T> valueClass, final Ref<ListBox<T>> list, final Ref<Integer> selectionIndex) {
		RefDefault<T> ref = RefDefault.create(valueClass, null);
		addReaction(ref, list, selectionIndex);
		return ref;
	}
	
	/**
	 * Create a {@link Ref} that will always contain the
	 * element of a {@link ListBox} that is chose by an
	 * integer selection index.
	 * 
	 * {@link Ref} will have null value class.
	 * 
	 * @param <T>				The type of element in the {@link ListBox} 
	 * @param list				The {@link Ref} to a {@link ListBox}
	 * @param selectionIndex	{@link Ref} to selected index
	 * @return					A {@link Ref} that always contains the selected element, or
	 * 							null if selectionIndex is -1 or outside list.
	 */
	public static <T> Ref<T> create(final Ref<ListBox<T>> list, final Ref<Integer> selectionIndex) {
		RefDefault<T> ref = RefDefault.create((T)null);
		addReaction(ref, list, selectionIndex);
		return ref;
	}
	
	private static <T> void addReaction(Ref<T> ref, final Ref<ListBox<T>> list, final Ref<Integer> selectionIndex) {
		new ReactionDefault<T>(new Source<T>() {
			@Override
			public T get() throws NoInstanceAvailableException {
				int currentIndex = selectionIndex.get();
				ListBox<T> currentList = list.get();
				if (currentList == null || currentIndex < 0 || currentIndex >= currentList.size()) {
					return null;
				}
				return currentList.get(currentIndex);
			}
		}, ref, list, selectionIndex);
	}
	
}
